package cn.csg.iotplatform.module.system.service.publicnotice;

import cn.csg.iotplatform.framework.common.exception.ErrorCode;
import cn.csg.iotplatform.framework.common.pojo.PageResult;
import cn.csg.iotplatform.framework.common.util.object.BeanUtils;
import cn.csg.iotplatform.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.csg.iotplatform.framework.mybatis.core.util.MyBatisUtils;
import cn.csg.iotplatform.framework.web.core.util.WebFrameworkUtils;
import cn.csg.iotplatform.module.common.query.QueryGenerator;
import cn.csg.iotplatform.module.system.controller.admin.publicnotice.vo.PublicNoticeListRepVO;
import cn.csg.iotplatform.module.system.controller.admin.publicnotice.vo.PublicNoticeListReqVO;
import cn.csg.iotplatform.module.system.controller.admin.publicnotice.vo.PublicNoticeSaveReqVO;
import cn.csg.iotplatform.module.system.controller.admin.publicnotice.vo.WorkFlowVO;
import cn.csg.iotplatform.module.system.dal.dataobject.projectcopy.ProjectDO;
import cn.csg.iotplatform.module.system.dal.dataobject.publicnotice.PublicNoticeDO;
import cn.csg.iotplatform.module.system.dal.dataobject.publicnotice.PublicNoticeDeptDO;
import cn.csg.iotplatform.module.system.dal.dataobject.user.AdminUserDO;
import cn.csg.iotplatform.module.system.dal.mysql.publicnotice.PublicNoticeDeptMapper;
import cn.csg.iotplatform.module.system.dal.mysql.publicnotice.PublicNoticeMapper;
import cn.csg.iotplatform.module.system.enums.flow.WorkFlowType;
import cn.csg.iotplatform.module.system.service.user.AdminUserService;
import cn.csg.iotplatform.module.workflow.api.task.BpmProcessInstanceApi;
import cn.csg.iotplatform.module.workflow.api.task.vo.BpmProcessInstancePageReqApiVO;
import cn.csg.iotplatform.module.workflow.api.task.vo.BpmProcessInstanceRespApiVO;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.util.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.csg.iotplatform.framework.common.exception.util.ServiceExceptionUtil.exception;

@Slf4j
@Service
public class PublicNoticeServiceImpl implements IPublicNoticeService {

    @Resource
    private PublicNoticeMapper publicNoticeMapper;
    @Resource
    private PublicNoticeDeptMapper publicNoticeDeptMapper;
    @Resource
    private AdminUserService adminUserService;

    @Resource
    private BpmProcessInstanceApi bpmProcessInstanceApi;

    @Override
    public int create(PublicNoticeSaveReqVO saveReqVO) {
        log.info("公告通知新增信息: {}", saveReqVO);
        Long userId = WebFrameworkUtils.getLoginUserId();
        AdminUserDO userDO = adminUserService.getUser(userId);
        String userName = userDO.getUsername();

        PublicNoticeDO publicNoticeDO = BeanUtils.toBean(saveReqVO, PublicNoticeDO.class);
        publicNoticeDO.setStarter(userName);
        if(publicNoticeDO.getStatus() == 1) {
            getWorkData(publicNoticeDO);
        }
        int result = publicNoticeMapper.insert(publicNoticeDO);
        if(result == 1){
            String[] deptIds = saveReqVO.getReceiveDeptIds().split(",");
            insertPublicNoticeDept(deptIds, publicNoticeDO.getId());
        }
        return result;
    }

    /**
     * 获取流程信息
     *
     * @param publicNoticeDO
     */
    private void getWorkData(PublicNoticeDO publicNoticeDO) {
        BpmProcessInstancePageReqApiVO apiVO = new BpmProcessInstancePageReqApiVO();
        apiVO.setBillNo(publicNoticeDO.getBillNo());
        apiVO.setFormType(2);
        BpmProcessInstanceRespApiVO respApiVO = bpmProcessInstanceApi.getProcessInstanceMyPage(apiVO);
        log.info("公告流程节点信息返回: {}", respApiVO);
        if(respApiVO == null) {
            throw exception("流程信息不存在请联系管理员");
        }
        if(CollectionUtils.isEmpty(respApiVO.getUserIds())) {
            throw exception("流程节点未配置审批人");
        }
        List<AdminUserDO> userList = adminUserService.getUserList(respApiVO.getUserIds());
        String userNames = userList.stream().map(AdminUserDO::getUsername).collect(Collectors.joining(","));
        publicNoticeDO.setProcessInstanceId(respApiVO.getProcessInstanceId());
        publicNoticeDO.setCurrentNode(respApiVO.getCurrentNode());
        publicNoticeDO.setTodoEmps(userNames);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(PublicNoticeSaveReqVO saveReqVO) {
        log.info("公告通知修改信息: {}", saveReqVO);
        PublicNoticeDO noticeDO = publicNoticeMapper.selectById(saveReqVO.getId());
        if(noticeDO == null) {
            throw exception("公告通知不存在");
        }
        PublicNoticeDO publicNoticeDO = BeanUtils.toBean(saveReqVO, PublicNoticeDO.class);
        if(noticeDO.getStatus() == 0 && publicNoticeDO.getStatus() == 1) {
            getWorkData(publicNoticeDO);
        }
        int result = publicNoticeMapper.updateById(publicNoticeDO);
        if(result == 1){
            publicNoticeDeptMapper.deleteByMap(Collections.singletonMap("NOTICE_ID", publicNoticeDO.getId()));
            String[] deptIds = saveReqVO.getReceiveDeptIds().split(",");
            insertPublicNoticeDept(deptIds, publicNoticeDO.getId());
        }
        return result;
    }

    @Override
    public boolean updateApprove(PublicNoticeDO publicNoticeDO) {
        log.info("公告通知审核修改信息: {}", publicNoticeDO);
        Long userId = WebFrameworkUtils.getLoginUserId();
        LambdaUpdateWrapper<PublicNoticeDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(PublicNoticeDO::getId, publicNoticeDO.getId());
        updateWrapper.set(PublicNoticeDO::getStatus, publicNoticeDO.getStatus());
        updateWrapper.set(PublicNoticeDO::getApproved, userId);
        updateWrapper.set(PublicNoticeDO::getApproveOpinion, publicNoticeDO.getApproveOpinion());
        updateWrapper.set(PublicNoticeDO::getApproveTime, new Date());
        updateWrapper.set(PublicNoticeDO::getUpdater, userId);
        updateWrapper.set(PublicNoticeDO::getUpdateTime, new Date());
        updateWrapper.set(PublicNoticeDO::getCurrentNode, "流程结束");
        return publicNoticeMapper.update(updateWrapper) > 0;

    }

    public void insertPublicNoticeDept(String[] deptIds, Long notionId) {
        List<PublicNoticeDeptDO> list = new ArrayList<>();
        for(String deptId : deptIds){
            PublicNoticeDeptDO publicNoticeDeptDO = PublicNoticeDeptDO.builder().noticeId(notionId).deptId(Long.parseLong(deptId)).build();
            list.add(publicNoticeDeptDO);
        }
        if(list.size() > 0){
            publicNoticeDeptMapper.insertBatch(list,500);
        }
    }

    @Override
    public PublicNoticeListRepVO get(Long id) {
        PublicNoticeListRepVO repVO = publicNoticeMapper.selectPublicNotice(id);
        PublicNoticeListRepVO unit = publicNoticeMapper.getReceiveDepts(repVO.getId());
        if(unit != null) {
            repVO.setReceiveDeptIds(unit.getReceiveDeptIds());
            repVO.setReceiveDepts(unit.getReceiveDepts());
        }
        return repVO;
    }

    @Override
    public void delete(Long id) {
        publicNoticeMapper.deleteById(id);
    }

    @Override
    public PageResult<PublicNoticeListRepVO> getList(PublicNoticeListReqVO reqVO) {
        Long userId = WebFrameworkUtils.getLoginUserId();
        AdminUserDO userDO = adminUserService.getUser(userId);
        String userName = userDO.getUsername();
        if(reqVO.getWorkFlowType() != null) {
            switch (WorkFlowType.values()[reqVO.getWorkFlowType()]){
                case MY_TODO:
                    reqVO.setTodoEmps(userName);
                    reqVO.setStatus(1);
                    break;
                case MY_CHECK:
                    reqVO.setApproved(userId+"");
                    break;
                case MY_START:
                    reqVO.setCreator(userId+"");
                    break;
                case ALL:
                    reqVO.setParticipant(userId + "");
                    reqVO.setStatus(2);
                    break;
                case BOARD:
                    reqVO.setStatus(2);
                    reqVO.setPublishTime(DateUtils.format(new Date()));
                    reqVO.setReceiveDept(userDO.getDeptId());
                    break;
            }
        }
        IPage<PublicNoticeListRepVO> page = new Page<>(reqVO.getPageNo(), reqVO.getPageSize());
        publicNoticeMapper.selectPublicNoticeList(page, reqVO);
        dealPublicNoticeList(page.getRecords(), reqVO, userName);
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    private void dealPublicNoticeList(List<PublicNoticeListRepVO> records, PublicNoticeListReqVO reqVO, String userName) {
        if(CollectionUtils.isNotEmpty(records)) {
            for(PublicNoticeListRepVO repVO : records) {
                if(StringUtils.isNotEmpty(repVO.getTodoEmps())) {
                    List<AdminUserDO> userList = adminUserService.getUserListByUserName(Arrays.asList(repVO.getTodoEmps().split(",")));
                    if(CollectionUtils.isNotEmpty(userList)) {
                        String nicknames = userList.stream().map(AdminUserDO::getNickname).collect(Collectors.joining(","));
                        repVO.setTodoEmpNames(nicknames);
                    }
                }
            }
        }
    }

/*    @Override
    public boolean updateWorkFlowInfo(WorkFlowVO workFlowVO) {
        log.info("公告通知修改信息: {}", workFlowVO);
        LambdaUpdateWrapper<PublicNoticeDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(PublicNoticeDO::getWorkFlowId, workFlowVO.getWorkFlowId());
        updateWrapper.set(PublicNoticeDO::getTodoEmps, workFlowVO.getTodoEmps());
        updateWrapper.set(PublicNoticeDO::getEmps, workFlowVO.getEmps());
        updateWrapper.set(PublicNoticeDO::getCurrentNode, workFlowVO.getCurrentNode());
        updateWrapper.set(PublicNoticeDO::getStarter, workFlowVO.getStarter());
        updateWrapper.set(PublicNoticeDO::getWfState, workFlowVO.getWfState());
        return publicNoticeMapper.update(updateWrapper) > 0;
    }*/
}
